home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 February / macformat-034.iso / mac / Shareware City / Developers / Floating.c ƒ / Floating.c next >
Encoding:
C/C++ Source or Header  |  1995-11-24  |  7.9 KB  |  324 lines  |  [TEXT/MPCC]

  1. /*
  2.     "Floating.c"
  3.     
  4.     This file offers substitute routines for commonly used calls to the
  5.     window manager in order to gain the advantage of supporting multiple
  6.     floating windows (such as an info window, a tool pallete, etc.)
  7. */
  8.  
  9. /*
  10.     Change History
  11.     (while in the hands of John DeWeese)
  12.     
  13.     8/30/95 -
  14.     Altered DragTheWindow to more closely emulate the standard DragWindow(),
  15.     added an if (StillDown()) after SelectTheWindow() to give it a time
  16.     cushioned effect.
  17.     
  18.     11/14/95 -
  19.     Commented out the ReactToRemoval() in the function HideTheWindow()
  20.     because of a display bug it cause on my PowerMac with System 7.5.
  21.     Since this bug was tested on other systems as well, I believe this
  22.     has cured it. If windows are not hiliting at all once one is closed,
  23.     this procedure may be suspect. Thus, it is simply commented.
  24.     
  25.     11/20/95 -
  26.     Removed the superfluous PaintOne() and CalcVis() from SelectTheWindow().
  27.     PaintOne() was the cause of a mysterious flicker upon update of the 
  28.     window, and CalcVis() seems to be docile, but uneccessary.
  29. */
  30.  
  31. #include "Floating.h"
  32.  
  33. // global variables
  34. WindowPtr bottomFloat;
  35. WindowPtr topFloat;
  36. WindowPtr topWindow;
  37.  
  38. /*
  39. ActivateWindow hilites/unhilites the window and then generates an
  40. activate/deactivate event for it. In order to generate activate
  41. events, it mucks with low-mem globals. It would be cleaner to
  42. directly call the activate routine for the window. The advantage
  43. of this method is that it also works with modeless dialogs.
  44. The Dialog Manager doesn't know that a dialog is active unless
  45. it actually receives an activate event.
  46. */
  47.  
  48. void ActivateWindow (WindowPtr window, Boolean on)
  49. {
  50.     WindowPtr *p;
  51.  
  52.     if (window != nil)
  53.     {
  54.         HiliteWindow(window, on);
  55.         if (on)
  56.             p = (WindowPtr *)(CurActivate);
  57.         else
  58.             p = (WindowPtr *)(CurDeactive);
  59.         p = &window;
  60.     }
  61. }
  62.  
  63. /*
  64. InitFloats is to be called at the beginning of the program,
  65. before creating any windows. It sets our global variables to nil.
  66. */
  67.  
  68. void InitFloats (void)
  69. {
  70.     topFloat = nil;
  71.     bottomFloat = nil;
  72.     topWindow = nil;
  73. }
  74.  
  75. /*
  76. IsFloating and IsVisible are little, foolproof routines that tell
  77. whether a window is floating or visible. Using them avoids errors
  78. such as examining WindowPeek(whichWindow)->visible when whichWindow == nil
  79. */
  80.  
  81. Boolean IsFloating (WindowPtr whichWindow)
  82. {
  83.     if (whichWindow == nil)
  84.         return false;
  85.     else
  86.         return (((WindowPeek)whichWindow)->windowKind == kFloatingKind);
  87. }
  88.  
  89. Boolean IsVisible (WindowPtr whichWindow)
  90. {
  91.     if (whichWindow == nil)
  92.         return false;
  93.     else
  94.         return (((WindowPeek)whichWindow)->visible);
  95. }
  96.  
  97. /*
  98. UpdateFloats updates the topFloat and bottomFloat variables by walking
  99. down the window list. It then determines topWindow by taking the first
  100. visible window after bottomFloat.
  101. */
  102.  
  103. void UpdateFloats (void)
  104. {
  105.     WindowPtr theWindow = FrontWindow();
  106.         
  107.     if (IsFloating(theWindow))
  108.     {
  109.         topFloat = theWindow;
  110.         while ((theWindow != nil) && (IsFloating(theWindow)))
  111.         {
  112.             bottomFloat = theWindow;
  113.             theWindow = (WindowPtr)(((WindowPeek)theWindow)->nextWindow);
  114.         }
  115.         
  116.         while ((theWindow != nil) && (!IsVisible(theWindow)))
  117.             theWindow = (WindowPtr)(((WindowPeek)theWindow)->nextWindow);
  118.         topWindow = theWindow;
  119.     }
  120.     else    
  121.     {
  122.         topFloat = nil;    
  123.         bottomFloat = nil;
  124.         topWindow = FrontWindow();
  125.     }
  126. }
  127.  
  128. /*
  129. MakeFloat turns a newly created window into a floating window and
  130. brings it to the front. The window must have been created via a call
  131. to [Get]NewWindow().
  132. */
  133.  
  134. void MakeFloat (WindowPtr theWindow)
  135. {
  136.     BringToFront(theWindow);
  137.     ShowHide(theWindow, true);
  138.     if (topFloat == nil)
  139.         bottomFloat = theWindow;    
  140.     topFloat = theWindow;
  141.     ((WindowPeek)theWindow)->windowKind = kFloatingKind;        
  142. }
  143.  
  144. /*
  145. ReactToRemoval handles a few necessary steps after killing whichWindow.
  146. underWindow is the window that was under whichWindow
  147. (i.e. next to it in the window list).
  148. */
  149.  
  150. void ReactToRemoval (WindowPeek underWindow)
  151. {
  152.     while ((underWindow != nil) && (!IsVisible((WindowPtr)underWindow)))
  153.     {
  154.         underWindow = underWindow->nextWindow;            
  155.     }
  156.     ActivateWindow((WindowPtr)underWindow, true);
  157.     UpdateFloats();
  158. }
  159.  
  160. void HideTheWindow (WindowPtr whichWindow)
  161. {
  162.     WindowPeek underWindow;    
  163.  
  164.     underWindow = ((WindowPeek)whichWindow)->nextWindow;        
  165.     HideWindow(whichWindow);
  166.     //ReactToRemoval(underWindow);
  167. }
  168.  
  169. void DisposeTheWindow (WindowPtr whichWindow)
  170. {
  171.     WindowPeek underWindow;
  172.  
  173.     underWindow = ((WindowPeek)whichWindow)->nextWindow;    
  174.     DisposeWindow(whichWindow);
  175.     ReactToRemoval(underWindow);
  176. }
  177.  
  178. /*
  179. SelectTheWindow is the most important routine. Here's what we do:
  180. If whichWindow is not visible, show it.
  181. - If whichWindow is a floating window, just bring it to the front.
  182. - If it is a regular window and there are no floating windows, bring
  183.    it to the front, activate it, deactivate the former front window.
  184. - If it is a regular window and there are floating windows, send it
  185.    behind bottomFloat, activate it, deactivate the old topWindow
  186. Finally, update the global float variables.
  187. */
  188.  
  189. void SelectTheWindow (WindowPtr whichWindow)
  190. {    
  191.     if (!(((WindowPeek)whichWindow)->visible))
  192.         ShowHide(whichWindow, true);
  193.  
  194.     if (IsFloating(whichWindow))
  195.     {
  196.         BringToFront(whichWindow);
  197.         HiliteWindow(whichWindow, true);
  198.     }
  199.     else
  200.     {
  201.         if (whichWindow != topWindow)
  202.         {    
  203.             if (bottomFloat != nil)                    
  204.             {
  205.                 SendBehind(whichWindow, bottomFloat);        
  206.                 //PaintOne(whichWindow, ((WindowPeek)whichWindow)->strucRgn);
  207.                 //CalcVis(whichWindow);
  208.             }
  209.             else
  210.                 BringToFront(whichWindow);
  211.  
  212.             ActivateWindow(whichWindow, true);
  213.             ActivateWindow(topWindow, false);
  214.         }
  215.     }
  216.     
  217.     UpdateFloats();
  218. }
  219.  
  220. /*
  221. DragTheWindow is to be called instead of DragWindow, because DragWindow
  222. brings the window to the front unless the command key is down. We use
  223. DragGrayRgn to drag a gray outline of the window. We clip the dragging
  224. to a region consisting of the whole desktop minus the windows that are
  225. in front of the window we're dragging. To emulate DragWindow's behavior,
  226. we send the window to the front, unless the command key is down.
  227. */
  228.  
  229. void DragTheWindow (WindowPtr whichWindow, EventRecord *Event)
  230. {
  231.     GrafPtr savePort;
  232.     GrafPort wPort;
  233.     Point thePoint;
  234.     long newLoc;
  235.     WindowPeek theWindow;
  236.     Rect dragRect;
  237.     RgnHandle dragRgn;
  238.     
  239.     if (!(Event->modifiers & cmdKey))
  240.         SelectTheWindow(whichWindow);
  241.     
  242.     if (StillDown())
  243.     {
  244.         GetPort(&savePort);
  245.         SetPort(whichWindow);
  246.         thePoint.h = whichWindow->portRect.left;
  247.         thePoint.v = whichWindow->portRect.top;
  248.         LocalToGlobal(&thePoint);
  249.         dragRgn = NewRgn();
  250.         CopyRgn(((WindowPeek)whichWindow)->strucRgn, dragRgn);
  251.         
  252.         OpenPort(&wPort);
  253.         CopyRgn(GetGrayRgn(), wPort.visRgn);
  254.         theWindow = (WindowPeek)(FrontWindow());
  255.         while (theWindow != ((WindowPeek)whichWindow))
  256.         {
  257.             DiffRgn(wPort.visRgn, theWindow->strucRgn, wPort.visRgn);
  258.             theWindow = theWindow->nextWindow;
  259.         }
  260.     
  261.         dragRect = (*GetGrayRgn())->rgnBBox;
  262.         InsetRect(&dragRect, 4, 4);
  263.         
  264.         // Here is the heart of the drag action. nil at the end is a space for a DragGrayRgnUPP
  265.         newLoc = DragGrayRgn(dragRgn, Event->where, &dragRect, &dragRect, noConstraint, nil);
  266.         if ((newLoc != cancelDrag) && (newLoc != 0))
  267.             MoveWindow(whichWindow, thePoint.h + LoWord(newLoc),
  268.                                                             thePoint.v + HiWord(newLoc), false);
  269.     
  270.         DisposeRgn(dragRgn);
  271.         ClosePort(&wPort);
  272.         SetPort(savePort);
  273.     }
  274.     else
  275.     {
  276.         SelectTheWindow(whichWindow);
  277.     }
  278. }
  279.  
  280. /*
  281. HideFloats/ShowFloats are simple routines that hide/show all floating
  282. windows. They're useful to handle suspend/resume events.
  283.  
  284. */
  285.  
  286. void HideFloats (void)
  287. {
  288.     while (IsFloating(FrontWindow()))    
  289.         HideWindow(FrontWindow());
  290.     //topFloat = nil;
  291.     //bottomFloat = nil;
  292. }
  293.  
  294. /*
  295. **************** Note ****************
  296. ShowFloats is buggy.
  297.  
  298. After calling ShowFloats, the window
  299. behind the topWindow is lost track of.
  300. Put another way, topWindow's 
  301. "nextWindow" is updated incorrectly.
  302. That means that even if new windows
  303. are created, that link is still lost.
  304. **************************************
  305. */
  306.  
  307. void ShowFloats (void)
  308. {
  309.     WindowPtr
  310.         theWindow,
  311.         *p;
  312.         
  313.     p = (WindowPtr *)(WindowList);
  314.     theWindow = (*p);
  315.     while (theWindow != nil)
  316.     {
  317.         if (IsFloating(theWindow))
  318.         {
  319.             ShowHide(theWindow, true);
  320.             HiliteWindow(theWindow, true);
  321.         }
  322.         theWindow = (WindowPtr)((WindowPeek)theWindow)->nextWindow;
  323.     }
  324. }